# coding: utf-8


class TokenType:

    # Служебные токены
    PARSER_EOF = -8  # Служебный EOF для парсера
    ERROR = -7  # Ошибка
    NONE = -6  # Не токен
    EOI = -5  # Конец потока
    TAB = -4  # Отступ, служебный токен сканера

    # Токены форматирования
    NEW_LINE = -3  # Конец строки
    TAB_INC = -2  # Увеличение отступа
    TAB_DEC = -1  # Уменьшение отступа

    # Незначащие токены
    WHITESPACE = 0  # Пробельный символ (пробел, перенос строки и т. д.)
    COMMENT = 1  # Комментарий типа этого

    # Переменные
    ID = 2  # Идентификатор
    VAL_INT = 3  # 123
    VAL_STR = 4  # "lol" или 'lol'

    # Операторы управления потоком выполнения
    IF = 5  # if
    ELIF = 6  # elif
    ELSE = 7  # else
    WHILE = 8  # while
    FOR = 9  # for
    IN = 10  # in
    DEF = 11  # def

    # Логические операторы
    TRUE = 12  # True
    FALSE = 13  # False
    AND = 14  # and
    OR = 15  # or
    NOT = 16  # not
    EQUAL = 17  # ==
    NOT_EQUAL = 40  # !=
    LESS = 18  # <
    MORE = 19  # >
    LESS_E = 20  # <=
    MORE_E = 21  # >=

    # Зарезервированные слова-операторы
    PASS = 22  # pass
    RETURN = 23  # return
    PRINT = 24  # print

    # Остальные операторы
    COLON = 25  # :
    ASSIGN = 26  # =
    PLUS = 27  # +
    MINUS = 28  # -
    MULT = 29  # *
    DIV = 30  # //
    BR_L = 31  # (
    BR_R = 32  # )
    BR_Q_L = 33  # [
    BR_Q_R = 34  # ]
    COMMA = 35  # ,
    ASSIGN_PLUS = 36  # +=
    ASSIGN_MINUS = 37  # -=
    ASSIGN_MULT = 38  # *=
    ASSIGN_DIV = 39  # /=


class Token(object):
    valuable_tokens = [TokenType.ID, TokenType.VAL_INT, TokenType.VAL_STR, TokenType.TRUE, TokenType.FALSE,
                       TokenType.AND, TokenType.OR, TokenType.NOT, TokenType.EQUAL, TokenType.NOT_EQUAL, TokenType.LESS,
                       TokenType.MORE, TokenType.LESS_E, TokenType.MORE_E, TokenType.PASS, TokenType.RETURN,
                       TokenType.PRINT, TokenType.ASSIGN, TokenType.PLUS, TokenType.MINUS, TokenType.MULT,
                       TokenType.DIV, TokenType.BR_Q_L, TokenType.BR_Q_R, TokenType.BR_L, TokenType.BR_R,
                       TokenType.ASSIGN_PLUS, TokenType.ASSIGN_MINUS, TokenType.ASSIGN_MULT, TokenType.ASSIGN_DIV,
                       TokenType.COMMA
    ]
    tokens_to_hide_finally = [TokenType.PRINT, TokenType.BR_L, TokenType.BR_R, TokenType.BR_Q_L, TokenType.BR_Q_R]
    variable_type = None
    line = None

    str_mapping = {
        TokenType.PARSER_EOF: "EOF",
        TokenType.ERROR: "ERROR",
        TokenType.NONE: "NONE",
        TokenType.EOI: "EOI",
        TokenType.TAB: "TAB",
        TokenType.NEW_LINE: "NEW_LINE",
        TokenType.TAB_INC: "TAB_INC",
        TokenType.TAB_DEC: "TAB_DEC",
        TokenType.WHITESPACE: "WHITESPACE",
        TokenType.COMMENT: "COMMENT",
        TokenType.ID: "ID",
        TokenType.VAL_INT: "VAL_INT",
        TokenType.VAL_STR: "VAL_STR",
        TokenType.IF: "IF",
        TokenType.ELIF: "ELIF",
        TokenType.ELSE: "ELSE",
        TokenType.WHILE: "WHILE",
        TokenType.FOR: "FOR",
        TokenType.IN: "IN",
        TokenType.DEF: "DEF",
        TokenType.TRUE: "TRUE",
        TokenType.FALSE: "FALSE",
        TokenType.AND: "AND",
        TokenType.OR: "OR",
        TokenType.NOT: "NOT",
        TokenType.EQUAL: "EQUAL",
        TokenType.NOT_EQUAL: "NOT_EQUAL",
        TokenType.LESS: "LESS",
        TokenType.MORE: "MORE",
        TokenType.LESS_E: "LESS_E",
        TokenType.MORE_E: "MORE_E",
        TokenType.PASS: "PASS",
        TokenType.RETURN: "RETURN",
        TokenType.PRINT: "PRINT",
        TokenType.COLON: "COLON",
        TokenType.ASSIGN: "ASSIGN",
        TokenType.PLUS: "PLUS",
        TokenType.MINUS: "MINUS",
        TokenType.MULT: "MULT",
        TokenType.DIV: "DIV",
        TokenType.BR_L: "BR_L",
        TokenType.BR_R: "BR_R",
        TokenType.BR_Q_L: "BR_Q_L",
        TokenType.BR_Q_R: "BR_Q_R",
        TokenType.COMMA: "COMMA",
        TokenType.ASSIGN_PLUS: "ASSIGN_PLUS",
        TokenType.ASSIGN_MINUS: "ASSIGN_MINUS",
        TokenType.ASSIGN_MULT: "ASSIGN_MULT",
        TokenType.ASSIGN_DIV: "ASSIGN_DIV",
    }

    def __init__(self, token_type=TokenType.NONE, token_value=None, token_line=None):
        self.type = token_type
        self.value = token_value
        self.line = token_line

    def __int__(self):
        return self.type

    def __repr__(self):
        result = "<" + self.type_string()
        if (self.type == TokenType.ID or
                    self.type == TokenType.VAL_INT or
                    self.type == TokenType.VAL_STR or
                    self.type == TokenType.COMMENT or
                    self.type == TokenType.ERROR):
            result += " value=" + str(self.value)
        result += " ({0})>".format(self.line)
        return result

    def value(self):
        """
        Возвращает значение токена (для ID, VAL_INT, VAL_STR, COMMENT и ERROR) """
        return self.value

    def type_string(self):
        """
        Возвращает строковое представление типа токена """
        return Token.str_mapping[self.type] or "Unknown"

    def is_valuable(self):
        return self.type in Token.valuable_tokens

    def needs_to_hide_finally(self):
        return self.type in Token.tokens_to_hide_finally

    def get_type(self):
        return self.type_string()